Исследуем отношение между переменными

Elements of Data Science, copyright 2021 Allen B. Downey

License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International

Подписка на онлайн-обучение telegram

Open in Colab

В этой главе исследуются отношения между переменными.

Самый важный урок этой главы заключается в том, что вы всегда должны визуализировать взаимосвязь между переменными, прежде чем пытаться ее количественно оценить; в противном случае вас могут ввести в заблуждение.

Изучение отношений

В качестве первого примера мы рассмотрим взаимосвязь между ростом и весом.

Мы будем использовать данные из Системы наблюдения за поведенческими факторами риска (BRFSS), которая находится в ведении Центров по контролю за заболеваниями по адресу https://www.cdc.gov/brfss.

В опросе приняли участие более 400 000 респондентов, но, чтобы произвести анализ, я выбрал случайную подвыборку из 100 000 человек.

Вот несколько строк:

BRFSS включает сотни переменных. Для примеров в этой главе я выбрал всего девять.

Мы начнем с HTM4, который записывает рост каждого респондента в см, и WTKG3, который записывает вес в кг.

Чтобы визуализировать взаимосвязь между этими переменными, мы построим диаграмму рассеяния (scatter plot).

Диаграммы рассеяния широко распространены и понятны, но их на удивление сложно правильно построить.

В качестве первой попытки мы будем использовать функцию plot с аргументом o, который строит круг для каждой точки.

см. документацию по plot

Похоже, что высокие люди тяжелее, но в этом графике есть несколько моментов, которые затрудняют интерпретацию.

Первый из них - перекрытие (overplotted), то есть точки данных накладываются друг на друга, поэтому вы не можете сказать, где много точек, а где только одна.

Когда это происходит, результаты могут вводить в заблуждение.

Один из способов улучшить график - использовать прозрачность (transparency), что мы можем сделать с помощью ключевого аргумента alpha. Чем ниже значение alpha, тем прозрачнее каждая точка данных.

Вот как это выглядит с alpha=0.02.

Уже лучше, но на графике так много точек данных, что диаграмма рассеяния все еще перекрывается. Следующим шагом будет уменьшение размеров маркеров.

При markersize=1 и низком значении alpha диаграмма рассеяния будет менее насыщенной.

Вот как это выглядит.

Уже лучше, но теперь мы видим, что точки строятся отдельными столбцами. Это потому, что большая часть высоты была указана в дюймах и преобразована в сантиметры.

Мы можем разбить столбцы, добавив к значениям некоторый случайный шум; по сути, мы заполняем округленные значения.

Такое добавление случайного шума называется дрожанием (jittering).

Дрожание - это добавление случайного шума к данным для предотвращения перекрытия статистических графиков. Если непрерывное измерение округлено до некоторой удобной единицы, может произойти перекрытие. Это приводит к превращению непрерывной переменной в дискретную порядковую переменную. Например, возраст измеряется в годах, а масса тела - в фунтах или килограммах. Если вы построите диаграмму разброса веса в зависимости от возраста для достаточно большой выборки людей, там может быть много людей, записанных, скажем, с 29 годами и 70 кг, и, следовательно, в этой точке будет нанесено много маркеров (29, 70).

Чтобы уменьшить перекрытие, вы можете добавить к данным небольшой случайный шум. Размер шума часто выбирается равным ширине единицы измерения. Например, к значению 70 кг вы можете добавить количество u , где u - равномерная случайная величина в интервале [-0,5, 0,5]. Вы можете обосновать дрожание, предположив, что истинный вес человека весом 70 кг с равной вероятностью находится в любом месте интервала [69,5, 70,5].

Контекст данных важен при принятии решения о дрожании. Например, возраст обычно округляется в меньшую сторону: 29-летний человек может праздновать свой 29-й день рождения сегодня или, возможно, ему исполнится 30 завтра, но ей все равно 29 лет. Следовательно, вы можете изменить возраст, добавив величину v , где v - равномерная случайная величина в интервале [0,1]. (Мы игнорируем статистически значимый случай женщин, которым остается 29 лет в течение многих лет!)

Источник: Jittering to prevent overplotting in statistical graphics

Мы можем использовать NumPy для добавления шума из нормального распределения со средним 0 и стандартным отклонением 2.

см. документацию NumPy

Вот как выглядит график с дрожащими (jittered) высотами.

Столбцы исчезли, но теперь мы видим, что есть строки, в которых люди округляют свой вес. Мы также можем исправить это с помощью дрожания веса.

Наконец, давайте увеличим масштаб области, где находится большинство точек данных.

Функции xlim и ylim устанавливают нижнюю и верхнюю границы для осей $x$ и $y$; в данном случае мы наносим рост от 140 до 200 сантиметров и вес до 160 килограмм.

Вот как это выглядит.

Теперь у нас есть достоверная картина взаимосвязи между ростом и весом.

Ниже вы можете увидеть вводящий в заблуждение график, с которого мы начали, и более надежный, которым мы закончили. Они явно разные, и они предлагают разные истории о взаимосвязи между этими переменными.

Смысл этого примера в том, что для создания эффективного графика разброса требуются некоторые усилия.

Упражнение: Набирают ли люди вес с возрастом? Мы можем ответить на этот вопрос, визуализировав взаимосвязь между весом и возрастом.

Но прежде чем строить диаграмму рассеяния, рекомендуется визуализировать распределения по одной переменной за раз. Итак, давайте посмотрим на возрастное распределение.

Набор данных BRFSS включает столбец AGE, который представляет возраст каждого респондента в годах. Чтобы защитить конфиденциальность респондентов, возраст округляется до пятилетних интервалов. AGE содержит середину интервалов (bins).

empiricaldist - библиотека Python, представляющая эмпирические функции распределения.

Упражнение: Теперь давайте посмотрим на распределение веса.

Столбец, содержащий вес в килограммах, - это WTKG3. Поскольку этот столбец содержит много уникальных значений, отображение его как функции вероятности (PMF) работает плохо.

Чтобы получить лучшее представление об этом распределении, попробуйте построить график функции распределения (Cumulative distribution function, CDF).

Вычислите функцию распределения (CDF) нормального распределения с тем же средним значением и стандартным отклонением и сравните его с распределением веса.

Подходит ли нормальное распределение для этих данных? А как насчет логарифмического преобразования весов?

Упражнение: Теперь давайте построим диаграмму разброса (scatter plot) для weight и age.

Отрегулируйте alpha и markersize, чтобы избежать наложения (overplotting). Используйте ylim, чтобы ограничить ось y от 0 до 200 килограммов.

Упражнение: В предыдущем упражнении возрасты указаны в столбцах, потому что они были округлены до 5-летних интервалов (bins). Если мы добавим дрожание (jitter), диаграмма рассеяния покажет взаимосвязь более четко.

Визуализация отношений

В предыдущем разделе мы использовали диаграммы разброса для визуализации взаимосвязей между переменными, а в упражнениях вы исследовали взаимосвязь между возрастом и весом. В этом разделе мы увидим другие способы визуализации этих отношений, в том числе диаграммы размаха и скрипичные диаграммы.

Я начну с диаграммы разброса веса в зависимости от возраста.

В этой версии диаграммы разброса я скорректировал дрожание весов, чтобы между столбцами оставалось пространство.

Это позволяет увидеть форму распределения в каждой возрастной группе и различия между группами.

С этой точки зрения кажется, что вес увеличивается до 40-50 лет, а затем начинает уменьшаться.

Если мы пойдем дальше, то сможем использовать ядерную оценку плотности (Kernel Density Estimation, KDE) для оценки функции плотности в каждом столбце и построения графика. И для этого есть название - скрипичная диаграмма (violin plot).

Библиотека Seaborn предоставляет функцию, которая создает скрипичную диаграмму, но прежде чем мы сможем ее использовать, мы должны избавиться от любых строк с пропущенными данными.

Вот так:

dropna() создает новый фрейм данных, который удаляет строки из brfss, где AGE или WTKG3 равны NaN.

Теперь мы можем вызвать функцию violinplot.

см. документацию по violinplot

Аргументы x и y означают, что нам нужно AGE на оси x и WTKG3 на оси y.

data - это только что созданный фрейм данных, который содержит переменные для отображения.

Аргумент inner=None немного упрощает график.

На рисунке каждая фигура представляет собой распределение веса в одной возрастной группе. Ширина этих форм пропорциональна предполагаемой плотности, так что это похоже на две вертикальные ядерные оценки плотности (KDE), построенные вплотную друг к другу (и залитые красивыми цветами).

Другой, связанный с этим способ просмотра данных, называется диаграмма размаха (ящик с усами, box plot).

Код для создания диаграммы размаха очень похож.

см. документацию по boxplot

Я включил аргумент whis=10, чтобы отключить функцию, которая нам не нужна.

Каждый прямоугольник представляет распределение веса в возрастной группе. Высота каждого прямоугольника представляет собой диапазон от 25-го до 75-го процентиля. Линия в середине каждого прямоугольника - это медиана. Шипы, торчащие сверху и снизу, показывают минимальное и максимальное значения.

На мой взгляд, этот график дает лучшее представление о взаимосвязи между весом и возрастом.

Для данных, которые склоняются к более высоким значениям, иногда полезно рассматривать их в логарифмической шкале.

Мы можем сделать это с помощью Pyplot-функции yscale.

Чтобы наиболее четко показать взаимосвязь между возрастом и весом, я бы использовал этот рисунок.

В следующих упражнениях у вас будет возможность создать скрипичную диаграмму и диаграмму размаха.

Упражнение: Ранее мы рассмотрели диаграмму рассеяния (scatter plot) по росту и весу и увидели, что более высокие люди, как правило, тяжелее. Теперь давайте более подробно рассмотрим диаграмму размаха (box plot).

Фрейм данных brfss содержит столбец с именем _HTMG10, который представляет высоту в сантиметрах, разбитую на группы по 10 см.

Предложение: если метки на оси x сталкиваются, вы можете повернуть их следующим образом:

plt.xticks(rotation='45')

Упражнение: В качестве второго примера давайте посмотрим на взаимосвязь между доходом (income) и ростом.

В BRFSS доход представлен как категориальная переменная; то есть респондентов относят к одной из 8 категорий доходов. Имя столбца - INCOME2.

Прежде чем связывать доход с чем-либо еще, давайте посмотрим на распределение, вычислив функцию вероятности (PMF).

Примечание: вы увидите, что около трети респондентов относятся к группе с самым высоким доходом; лучше, если бы было больше лидирующих групп, но мы будем работать с тем, что у нас есть.

Упражнение: Создайте скрипичную диаграмму (violin plot), которая показывает распределение роста в каждой группе дохода.

Вы видите взаимосвязь между этими переменными?

Корреляция

В предыдущем разделе мы визуализировали отношения между парами переменных. Теперь мы узнаем о коэффициенте корреляции, который количественно определяет силу этих взаимосвязей.

Когда люди говорят "корреляция", они имеют в виду любую связь между двумя переменными. В статистике обычно это означает коэффициент корреляции Пирсона, который представляет собой число от -1 до 1, которое количественно определяет силу линейной связи между переменными.

Для демонстрации я выберу три столбца из набора данных BRFSS:

Результатом является фрейм данных только с этими столбцами.

С этим подмножеством данных мы можем использовать метод corr, например:

Результатом является корреляционная матрица. В первой строке корреляция HTM4 с самим собой равна 1. Это ожидаемо; корреляция чего-либо с самим собой равна 1.

Следующая запись более интересна; соотношение роста и веса составляет около 0.47. Коэффициент положительный, это означает, что более высокие люди тяжелее, и он умеренный по силе, что означает, что он имеет некоторую прогностическую ценность. Если вы знаете чей-то рост, вы можете лучше предположить его вес, и наоборот.

Корреляция между ростом и возрастом составляет примерно -0.09. Коэффициент отрицательный, это означает, что пожилые люди, как правило, ниже ростом, но он слабый, а это означает, что знание чьего-либо возраста не поможет, если вы попытаетесь угадать их рост.

Корреляция между возрастом и весом еще меньше. Напрашивается вывод, что нет никакой связи между возрастом и весом, но мы уже видели, что она есть. Так почему же корреляция такая низкая?

Помните, что зависимость между весом и возрастом выглядит так.

Люди за сорок - самые тяжелые; люди младшего и старшего возраста легче. Итак, эта связь нелинейна.

Но корреляция измеряет только линейные отношения. Если связь нелинейная, корреляция обычно недооценивает ее силу.

Чтобы продемонстрировать, я сгенерирую несколько поддельных данных: xs содержит точки с равным интервалом между -1 и 1.

ys - это квадрат xs плюс некоторый случайный шум.

Вот диаграмма рассеяния для xs и ys.

Понятно, что это сильная связь; если вам дано x, вы можете гораздо лучше догадаться о y.

Но вот корреляционная матрица:

Несмотря на то, что существует сильная нелинейная зависимость, вычисленная корреляция близка к 0.

В общем, если корреляция высока, то есть близка к 1 или -1, вы можете сделать вывод, что существует сильная линейная зависимость. Но если корреляция близка к 0, это не означает, что связи нет; может быть связь нелинейная.

Это одна из причин, по которой я считаю, что корреляция не является хорошей статистикой.

В частности, корреляция ничего не говорит о наклоне. Если мы говорим, что две переменные коррелируют, это означает, что мы можем использовать одну для предсказания другой. Но, возможно, это не то, о чем мы заботимся.

Например, предположим, что нас беспокоит влияние увеличения веса на здоровье, поэтому мы строим график зависимости веса от возраста от 20 до 50 лет.

Я создам два поддельных набора данных, чтобы продемонстрировать суть дела. В каждом наборе данных xs представляет возраст, а ys - вес.

Я использую np.random.seed для инициализации генератора случайных чисел, поэтому мы получаем одни и те же результаты при каждом запуске.

А вот и второй набор данных:

Я построил эти примеры так, чтобы они выглядели одинаково, но имели существенно разные корреляции:

В первом примере сильная корреляция, близкая к 0.75. Во втором примере корреляция умеренная, близкая к 0.5. Поэтому мы можем подумать, что первые отношения более важны. Но посмотрите внимательнее на ось y на обоих рисунках.

В первом примере средняя прибавка в весе за 30 лет составляет менее 1 килограмма; во втором больше 5 килограммов!

Если нас беспокоит влияние увеличения веса на здоровье, второе соотношение, вероятно, более важно, даже если корреляция ниже.

Статистика, которая нас действительно волнует, - это наклон линии, а не коэффициент корреляции.

В следующем разделе мы увидим, как оценить этот наклон. Но сначала давайте попрактикуемся с корреляцией.

Упражнения: Цель BRFSS - изучить факторы риска для здоровья, поэтому в него включены вопросы о диете.

Столбец _VEGESU1 представляет количество порций овощей, которые респонденты ели в день.

Посмотрим, как эта переменная связана с возрастом и доходом.

Упражнение: В предыдущем упражнении корреляция между доходом и потреблением овощей составляет около 0.12. Корреляция между возрастом и потреблением овощей составляет примерно -0.01.

Что из следующего является правильной интерпретацией этих результатов?

Упражнение: В общем, рекомендуется визуализировать взаимосвязь между переменными перед вычислением корреляции. В предыдущем примере мы этого не делали, но еще не поздно.

Создайте визуализацию взаимосвязи между возрастом и овощами. Как бы вы описали отношения, если они есть?

Простая регрессия

В предыдущем разделе мы видели, что корреляция не всегда измеряет то, что мы действительно хотим знать. В этом разделе мы рассмотрим альтернативу: простую линейную регрессию.

Давайте еще раз посмотрим на взаимосвязь между весом и возрастом. В предыдущем разделе я создал два фальшивых набора данных, чтобы доказать свою точку зрения:

Тот, что слева, имеет более высокую корреляцию, около 0,75 по сравнению с 0,5.

Но в этом контексте статистика, которая нас, вероятно, волнует, - это наклон линии, а не коэффициент корреляции.

Чтобы оценить наклон, мы можем использовать linregress из SciPy-библиотеки stats.

см. документацию по scipy.stats.linregress

Результатом является объект LinregressResult, содержащий пять значений: slope - наклон линии, наиболее подходящей для данных; intercept - это пересечение линии регрессии.

Для фальшивого набора данных 1 расчетный наклон составляет около 0,019 кг в год или около 0,56 кг за 30-летний период.

Вот результаты для фальшивого набора данных 2.

Расчетный наклон почти в 10 раз выше: около 0,18 килограмма в год или около 5,3 килограмма за 30 лет:

То, что здесь называется rvalue, - это корреляция, которая подтверждает то, что мы видели раньше; первый пример имеет более высокую корреляцию, около 0,75 по сравнению с 0,5.

Но сила эффекта, измеренная по наклону линии, во втором примере примерно в 10 раз выше.

Мы можем использовать результаты linregress для вычисления линии тренда: сначала мы получаем минимум и максимум наблюдаемых xs; затем мы умножаем на наклон и добавляем точку пересечения.

Вот как это выглядит для первого примера.

То же самое и со вторым примером.

Визуализация здесь может ввести в заблуждение, если вы не посмотрите внимательно на вертикальные шкалы; наклон на втором рисунке почти в 10 раз больше.

Рост и вес

Теперь рассмотрим пример с реальными данными. Вот еще раз диаграмма рассеяния для роста и веса.

Теперь мы можем вычислить линию регрессии. linregress не может обрабатывать значения NaN, поэтому мы должны использовать dropna для удаления строк, в которых отсутствуют нужные нам данные.

Теперь мы можем вычислить линейную регрессию.

Наклон составляет около 0,92 килограмма на сантиметр, а это означает, что мы ожидаем, что человек выше на один сантиметр будет почти на килограмм тяжелее. Это довольно много.

Как и раньше, мы можем вычислить линию тренда:

А вот как это выглядит.

Наклон этой линии соответствует диаграмме рассеяния.

Линейная регрессия имеет ту же проблему, что и корреляция; она только измеряет силу линейной связи.

Вот диаграмма рассеяния веса по сравнению с возрастом, которую мы видели ранее.

Люди в возрасте от 40 - самые тяжелые; люди младшего и старшего возраста легче. Так что отношения нелинейные.

Если мы не посмотрим на диаграмму рассеяния и вслепую вычислим линию регрессии, мы получим вот что.

Расчетный уклон составляет всего 0,02 килограмма в год или 0,6 килограмма за 30 лет.

А вот как выглядит линия тренда.

Прямая линия плохо отражает взаимосвязь между этими переменными.

Давайте попрактикуемся в простой регрессии.

Упражнение: Как вы думаете, кто ест больше овощей, люди с низким доходом или люди с высоким доходом? Давайте выясним.

Как мы видели ранее, столбец INCOME2 представляет уровень дохода, а _VEGESU1 представляет количество порций овощей, которые респонденты ели в день.

Постройте диаграмму рассеяния порций овощей в зависимости от дохода, то есть с порциями овощей по оси y и группой доходов по оси x.

Вы можете использовать ylim для увеличения нижней половины оси y.

Упражнение: Теперь давайте оценим наклон зависимости между потреблением овощей и доходом.

Каков наклон линии регрессии? Что означает этот наклон в контексте изучаемого нами вопроса?

Упражнение: Наконец, постройте линию регрессии поверх диаграммы рассеяния.

Подписка на онлайн-обучение telegram